package com.ZeroCarbon.service.impl;

import com.ZeroCarbon.common_service.CommonService;
import com.ZeroCarbon.domain.dto.CommentDTO;
import com.ZeroCarbon.domain.dto.UsernameAndAvatarDTO;
import com.ZeroCarbon.domain.po.Comment;
import com.ZeroCarbon.exception.BusinessLogicException;
import com.ZeroCarbon.mapper.CommentMapper;
import com.ZeroCarbon.service.ICommentService;
import com.ZeroCarbon.service.IUserCommentService;
import com.ZeroCarbon.utils.BusinessMethodUtils;
import com.ZeroCarbon.utils.UserHolder;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.ZeroCarbon.BusinessUtils.UserClientUtils.*;
import static com.ZeroCarbon.exception.BusinessLogicException.BUSY_EXCEPTION;
import static com.ZeroCarbon.exception.BusinessLogicException.ERROR_EXCEPTION;
import static com.ZeroCarbon.method.RemoteClientCall.OperationType.GET_AVATAR;
import static com.ZeroCarbon.method.RemoteClientCall.OperationType.GET_USERNAME;
import static com.ZeroCarbon.prefix.MySqlKey.COMMENT_PREFIX;
import static com.ZeroCarbon.prefix.MySqlKey.generateId;
import static com.ZeroCarbon.prefix.RedisKey.THUMB_COMMENT;
import static com.ZeroCarbon.utils.BusinessMethodUtils.copyOriginToTargetList;

@Service
@RequiredArgsConstructor
public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> implements ICommentService {

    private final IUserCommentService userCommentService;

    private final StringRedisTemplate redis;

    private CommonService<Comment> serviceUtils;

    @Autowired
    public void initServiceUtils(CommentMapper commentMapper) {
        serviceUtils = new CommonService<>(commentMapper);
    }

    /**
     * 发表评论
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void postComment(Comment comment) throws BusinessLogicException {
        //生成评论id
        String id = generateId(COMMENT_PREFIX);
        //填充评论信息
        comment.setLiked(0)
                .setDay(LocalDateTime.now())
                .setId(id);
        try {
            //保存评论失败
            if (!save(comment) || !userCommentService.postComment(id)) {
                throw new BusinessLogicException(ERROR_EXCEPTION);
            }
        } catch (BusinessLogicException e) {
            throw new BusinessLogicException(ERROR_EXCEPTION);
        }
    }

    /**
     * 获取评论
     */
    @Override
    public List<CommentDTO> getComments(String id) throws BusinessLogicException {
        //查找当前记录所有评论id
        LambdaQueryWrapper<Comment> getCommentsWrapper = new LambdaQueryWrapper<Comment>()
                .eq(Comment::getRecordId, id);
        //记录评论列表
        List<CommentDTO> commentDTOList;
        try {
            //拷贝数据
            commentDTOList = copyOriginToTargetList(list(getCommentsWrapper), CommentDTO.class);
        } catch (Exception e) {
            throw new BusinessLogicException(ERROR_EXCEPTION);
        }
        //对数据进行流处理
        commentDTOList = commentDTOList.stream()
                .map((commentDTO -> {
                    //记录用户名和头像信息
                    UsernameAndAvatarDTO avatarAndUsername;
                    try {
                        //获取用户名和头像
                        avatarAndUsername = getAvatarAndUsername(commentDTO.getId());
                    } catch (BusinessLogicException e) {
                        throw new RuntimeException(BUSY_EXCEPTION);
                    }
                    //设置评论的一些信息
                    return commentDTO.setAvatar(avatarAndUsername.getAvatar())
                            .setUsername(avatarAndUsername.getUsername())
                            .setUserId(avatarAndUsername.getUserId());
                })).collect(Collectors.toList());
        //判断评论集合是否为空
        if (commentDTOList.isEmpty()) {
            return Collections.emptyList();
        }
        return commentDTOList;
    }

    /**
     * 点赞评论
     */
    @Override
    public Integer thumbsUpComment(String id) throws BusinessLogicException {
        //用户id
        String userId = UserHolder.getUser();
        //评论key
        String key = THUMB_COMMENT + id;
        //点赞数查找器
        LambdaQueryWrapper<Comment> likedWrapper = new LambdaQueryWrapper<Comment>()
                .select(Comment::getLiked).eq(Comment::getId, id);
        //已点赞再次点击则取消赞
        int step = BusinessMethodUtils.isExist(key, userId) ? -1 : 1;
        //更新点赞
        Boolean isSuccess = serviceUtils.updateSqlIncrementOrCheck("liked", step, id);
        //修改redis中的记录
        if (step > 0 && isSuccess) {
            redis.opsForSet().remove(key, userId);
        } else {
            redis.opsForSet().add(key, userId);
        }
        try {
            //获取点赞数
            return getOne(likedWrapper).getLiked();
        } catch (Exception e) {
            throw new BusinessLogicException(ERROR_EXCEPTION);
        }
    }

    /**
     * 删除评论
     */
    @Override
    public void deleteComment(String id) throws BusinessLogicException {
        //删除redis相关评论键
        String key = THUMB_COMMENT + id;
        try {
            //删除键
            redis.delete(key);
            //删除失败抛出异常
            if (!removeById(id)) {
                throw new BusinessLogicException();
            }
        } catch (BusinessLogicException e) {
            throw new BusinessLogicException(ERROR_EXCEPTION);
        }
    }

    /**
     * 判断当前用户是否点赞评论
     *
     * @return true为已点赞 false为未点赞
     */
    @Override
    public Boolean isUserLikeComment(String id) {
        //获取用户id
        String userId = UserHolder.getUser();
        //获取key
        String key = THUMB_COMMENT + id;
        //判断当前用户是否点赞评论
        return BusinessMethodUtils.isExist(key, userId);
    }

    /**
     * 获取评论对应的头像和用户名
     *
     * @param id 评论id
     */
    private UsernameAndAvatarDTO getAvatarAndUsername(String id) throws BusinessLogicException {
        //用户信息map表
        Map<String, String> userClientInformation;
        try {
            //获取用户名和头像
            userClientInformation = getUserClientInformation(id, GET_USERNAME, GET_AVATAR);
        } catch (Exception e) {
            throw new BusinessLogicException(BUSY_EXCEPTION);
        }
        //设置额外信息返回
        return new UsernameAndAvatarDTO(id,
                userClientInformation.get(USERNAME),
                userClientInformation.get(AVATAR));
    }
}
